<?php

namespace application\modules\dashboard\controllers;

use application\core\utils\Cache as CacheUtil;
use application\core\utils\Env;
use application\core\utils\File;
use application\core\utils\IBOS;
use application\core\utils\Module;
use application\core\utils\Org;
use application\core\utils\StringUtil;
use application\core\utils\Upgrade;
use application\modules\dashboard\controllers\BaseController;
use application\modules\dashboard\model\Cache;
use application\modules\main\model\Setting;

class UpgradeController extends BaseController {

    /**
     * 必须是本地引擎才能进行此操作
     */
    public function init() {
        parent::init();
        if ( !LOCAL ) {
            die( IBOS::lang( 'Not compatible service', 'message' ) );
        }
    }

    public function actionIndex() {
        if ( Env::getRequest( 'op' ) ) {
            $operation = Env::getRequest( 'op' );
            $operations = array( 'checking', 'patch', 'showupgrade' );
            if ( !in_array( $operation, $operations ) ) {
                exit();
            }
            switch ( $operation ) {
                case 'checking': // 第一步：检查更新
                    $upgradeStep = Cache::model()->fetchByPk( 'upgrade_step' );
                    $upgradeStep['cachevalue'] = StringUtil::utf8Unserialize( $upgradeStep['cachevalue'] );
                    $isExistStep = !empty( $upgradeStep['cachevalue'] ) && !empty( $upgradeStep['cachevalue']['step'] );
                    // 查找步骤缓存
                    if ( !Env::getRequest( 'rechecking' ) && $isExistStep ) {
                        // 步骤缓存的URL参数
                        $param = array(
                            'op' => $upgradeStep['cachevalue']['operation'],
                            'version' => $upgradeStep['cachevalue']['version'],
                            'locale' => $upgradeStep['cachevalue']['locale'],
                            'charset' => $upgradeStep['cachevalue']['charset'],
                            'release' => $upgradeStep['cachevalue']['release'],
                            'step' => $upgradeStep['cachevalue']['step']
                        );
                        $data = array(
                            'url' => $this->createUrl( 'upgrade/index', $param ),
                            'stepName' => Upgrade::getStepName( $upgradeStep['cachevalue']['step'] )
                        );
                        $this->render( 'upgradeContinue', array( 'data' => $data ) );
                    } else { // 否则如果是重新请求更新或者步骤缓存为空，都做重新检查
                        Cache::model()->deleteByPk( 'upgrade_step' );
                        Upgrade::checkUpgrade();
                        $url = $this->createUrl( 'upgrade/index', array( 'op' => 'showupgrade' ) );
                        $this->redirect( $url );
                    }
                    break;
                case 'showupgrade': // 如有更新，进入第二步：显示更新列表
                    $result = $this->processingUpgradeList();
                    if ( $result['isHaveUpgrade'] ) {
                        $this->render( 'upgradeShow', $result );
                    } else {
                        $this->render( 'upgradeNewest' );
                    }
                    break;
                case 'patch': // 升级补丁
                    $step = Env::getRequest( 'step' );
                    $step = intval( $step ) ? $step : 1;
                    $version = trim( $_GET['version'] );
                    $release = trim( $_GET['release'] );
                    $locale = trim( $_GET['locale'] );
                    $charset = trim( $_GET['charset'] );
                    $upgradeInfo = $upgradeStep = array();
                    $upgradeStepRecord = Cache::model()->fetchByPk( 'upgrade_step' );
                    $upgradeStep = StringUtil::utf8Unserialize( $upgradeStepRecord['cachevalue'] );

                    // 初始化更新步骤
                    $upgradeStep['step'] = isset( $upgradeStep['step'] ) ? intval( $upgradeStep['step'] ) : $step;
                    $upgradeStep['operation'] = $operation;
                    $upgradeStep['version'] = $version;
                    $upgradeStep['release'] = $release;
                    $upgradeStep['charset'] = $charset;
                    $upgradeStep['locale'] = $locale;
                    $data = array(
                        'cachekey' => 'upgrade_step',
                        'cachevalue' => serialize( $upgradeStep ),
                        'dateline' => TIMESTAMP,
                    );
                    Cache::model()->add( $data, false, true ); //有则更新，无则插入
                    // 初始化更新所需信息
                    $upgradeRun = Cache::model()->fetchByPk( 'upgrade_run' );
                    if ( !$upgradeRun ) {
                        $upgrade = IBOS::app()->setting->get( 'setting/upgrade' );
                        $data = array(
                            'cachekey' => 'upgrade_run',
                            'cachevalue' => serialize( $upgrade ),
                            'dateline' => TIMESTAMP
                        );
                        Cache::model()->add( $data, false, true );
                        $upgradeRun = $upgrade;
                    } else {
                        $upgradeRun = StringUtil::utf8Unserialize( $upgradeRun['cachevalue'] );
                    }
                    // 下一步所需URL参数
                    $param = array(
                        'op' => $operation,
                        'version' => $version,
                        'locale' => $locale,
                        'charset' => $charset,
                        'release' => $release
                    );
                    // 开始处理升级步骤前的预处理
                    if ( $step != 5 ) {
                        $upgradeInfo = $this->filterRun( $param, $upgradeRun );
                        // 如果上次更新在第4步中断，可能会导致version文件版本与数据库缓存保存的数据对应不上
                        if ( empty( $upgradeInfo ) ) {
                            Cache::model()->deleteByPk( 'upgrade_step' );
                            Cache::model()->deleteByPk( 'upgrade_run' );
                            $msg = IBOS::lang( 'upgrade_unknow_error', '', array(
                                        '{url}' => $this->createUrl( 'upgrade/index', array( 'op' => 'checking', 'rechecking' => 1 ) ) )
                            );
                            $this->render( 'upgradeError', array( 'msg' => $msg ) );
                            exit;
                        }
                        $savePath = '/data/update/IBOS' . $upgradeInfo['latestversion'] . ' Release[' . $upgradeInfo['latestrelease'] . ']';
                        $fileList = Upgrade::fetchUpdateFileList( $upgradeInfo );
                        $updateMd5FileList = $fileList['md5'];
                        $updateFileList = $fileList['file'];
                        $preStatus = $this->preProcessingStep( $upgradeInfo, $actionUrl = $this->createUrl( 'upgrade/index', $param ), !empty( $updateFileList ) ? true : false  );
                        if ( $preStatus['status'] < 0 ) {
                            $this->ajaxReturn( $preStatus, 'json' );
                        }
                    }
                    // 开始步骤处理
                    switch ( $step ) {
                        case 1: // 第一步：显示更新文件
                            return $this->processingShowUpgrade( $updateFileList, $param, $savePath );
                            break;
                        case 2: // 第二步：下载文件
                            return $this->processingDownloadFile( $upgradeInfo, $updateMd5FileList, $updateFileList, $param );
                            break;
                        case 3: // 第三步：对比文件
                            return $this->processingCompareFile( $updateFileList, $param, $savePath );
                            break;
                        case 4: // 第四步：应用更新文件
                            return $this->processingUpdateFile( $upgradeInfo, $updateFileList, $upgradeStep, $param );
                            break;
                        case 5:// 第五步：删除临时下载文件，更新完成
                            return $this->processingTempFile( $param );
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        } else {
            $this->render( 'upgradeCheckVersion' );
        }
    }

    /**
     * 筛选当前更新的步骤信息
     * @param array $param 用于筛选对比的参数数组
     * @param array $upgradeRun 当前步骤信息
     * @return array
     */
    private function filterRun( $param, $upgradeRun ) {
        $upgradeInfo = array();
        if ( !empty( $upgradeRun ) ) {
            foreach ( $upgradeRun as $type => $list ) {
                if ( $type == $param['op'] && $param['version'] == $list['latestversion'] && $param['release'] == $list['latestrelease'] ) {
                    Upgrade::$locale = $param['locale'];
                    Upgrade::$charset = $param['charset'];
                    $upgradeInfo = $list;
                    break;
                }
            }
        }
        return $upgradeInfo;
    }

    /**
     * 开始更新步骤处理前的预处理
     * @param type $upgradeInfo
     * @param type $actionUrl
     * @param type $fileListExists
     * @return type
     */
    private function preProcessingStep( $upgradeInfo, $actionUrl, $fileListExists ) {
        // 没有文件更新
        if ( !$upgradeInfo ) {
            return array( 'status' => -1, 'msg' => IBOS::lang( 'Upgrade none' ) );
        }
        // 无法找到更新列表
        if ( !$fileListExists ) {
            return array( 'status' => -2, 'msg' => IBOS::lang( 'Upgrade download upgradelist error' ), 'actionUrl' => $actionUrl );
        }
        return array( 'status' => 1 );
    }

    /**
     * 处理升级内容列表
     * @return array 结果数组 e.g : array('isHaveUpgrade' => true, list => array(...));
     */
    private function processingUpgradeList() {
        $upgrades = IBOS::app()->setting->get( 'setting/upgrade' );
        if ( !$upgrades ) {
            return array( 'isHaveUpgrade' => false, 'msg' => IBOS::lang( 'Upgrade latest version' ) );
        } else {
            // 有更新，即存入缓存表备用
            $upgradeStep = array(
                'cachekey' => 'upgrade_step',
                'cachevalue' => serialize( array(
                    'curversion' => Upgrade::getVersionPath(),
                    'currelease' => VERSION_DATE )
                ),
                'dateline' => TIMESTAMP,
            );
            Cache::model()->add( $upgradeStep, false, true );
            // -----------------------
            $upgradeRow = array();
            $charset = str_replace( '-', '', strtoupper( CHARSET ) );
            $dbVersion = IBOS::app()->db->getServerVersion();
            // 确定更新地区目录
            $locale = '';
            if ( $charset == 'BIG5' ) {
                $locale = 'TC';
            } elseif ( $charset == 'GBK' ) {
                $locale = 'SC';
            } elseif ( $charset == 'UTF8' ) {
                $language = IBOS::app()->getLanguage();
                if ( $language == 'zh_cn' ) {
                    $locale = 'SC';
                } elseif ( $language == 'zh_tw' ) {
                    $locale = 'TC';
                }
            }
            foreach ( $upgrades as $type => $upgrade ) {
                $unUpgrade = 0;
                if ( version_compare( $upgrade['phpversion'], PHP_VERSION ) > 0 ||
                        version_compare( $upgrade['mysqlversion'], $dbVersion ) > 0 ) {
                    $unUpgrade = 1;
                }
                $baseDesc = 'IBOS ' . $upgrade['latestversion'] . '_' .
                        $locale . '_' . $charset .
                        ' [' . $upgrade['latestrelease'] . ']';
                // 未达到版本要求的提示
                if ( $unUpgrade ) {
                    $this->render( 'upgradeError', array( 'msg' => IBOS::lang( 'Upgrade require config', '', array( 'phpVersion' => PHP_VERSION, 'dbVersion' => $dbVersion ) ) ) );
                    exit;
                } else {
                    $params = array(
                        'op' => $type,
                        'version' => $upgrade['latestversion'],
                        'locale' => $locale,
                        'charset' => $charset,
                        'release' => $upgrade['latestrelease']
                    );
                    $linkUrl = $this->createUrl( 'upgrade/index', $params );
                    $upgradeRow[] = array(
                        'desc' => $baseDesc,
                        'upgrade' => true,
                        'link' => $linkUrl,
                        'upgradeDesc' => $upgrade['upgradeDesc'],
                        'official' => $upgrade['official']
                    );
                }
            }
            return array( 'isHaveUpgrade' => true, 'list' => $upgradeRow );
        }
    }

    /**
     * 更新第一步：显示更新列表
     * @param array $updateFileList 当前可以更新的文件列表
     * @param array $urlParam url参数数组，用于生成并返回下一步链接
     * @param string $savePath 显示更新文件保存路径
     * @return JsonString
     */
    private function processingShowUpgrade( $updateFileList, $urlParam = array(), $savePath = '' ) {
        $urlParam['step'] = 2;
        $url = $this->createUrl( 'upgrade/index', $urlParam );
        $data = array_merge( array( 'actionUrl' => $url ), array( 'list' => $updateFileList ), array( 'savePath' => $savePath ) );
        $this->render( 'upgradeDownloadList', array( 'step' => 1, 'data' => $data ) );
    }

    /**
     * 更新第二步：下载文件
     * @param array $upgradeInfo 更新所需信息
     * @param array $updateMd5FileList 可更新文件的md5列表
     * @param array $updateFileList 可更新文件列表
     * @param array $urlParam url参数数组，用于生成并返回下一步链接
     * @return JsonString
     */
    private function processingDownloadFile( $upgradeInfo, $updateMd5FileList, $updateFileList, $urlParam ) {
        if ( Env::getRequest( 'downloadStart' ) ) {
            // 文件列表索引
            $fileSeq = intval( Env::getRequest( 'fileseq' ) );
            // 默认第1个（实际数组从0开始，所以下载时需要减1）
            $fileSeq = $fileSeq ? $fileSeq : 1;
            // 文件指针，用于断点下载
            $position = intval( Env::getRequest( 'position' ) );
            $position = $position ? $position : 0;
            // 文件最大长度，如果下载的文件超过这个长度，则自动使用断点下载
            $offset = 100 * 1024;
            $data['step'] = 2;
            // 所有文件更新完成后，更新固定的特殊文件
            if ( $fileSeq > count( $updateFileList ) ) {
                // 如果有更新数据库
                if ( $upgradeInfo['isupdatedb'] ) {
//					Upgrade::downloadFile( $upgradeInfo, 'install/data/install.sql' );
//					Upgrade::downloadFile( $upgradeInfo, 'install/data/installData.sql' );
                    // 执行数据库表升级的文件
                    Upgrade::downloadFile( $upgradeInfo, 'update.php', 'utils' );
                }
                $data['data'] = array(
                    'IsSuccess' => true,
                    'msg' => IBOS::lang( 'Upgrade download complete to compare' ),
                    'url' => $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 3 ), $urlParam ) )
                );
                $data['step'] = 3;
                return $this->ajaxReturn( $data, 'json' );
            } else {
                // 当前文件
                $curFile = $updateFileList[$fileSeq - 1];
                // 当前MD5
                $curMd5File = $updateMd5FileList[$fileSeq - 1];
                // 当前进度百分比
                $percent = sprintf( "%2d", 100 * $fileSeq / count( $updateFileList ) ) . '%';
                $percent2 = $fileSeq . "/" . count( $updateFileList );
                // 开始下载并返回下载状态
                $downloadStatus = Upgrade::downloadFile( $upgradeInfo, $curFile, 'upload', $curMd5File, $position, $offset );
                if ( $downloadStatus == 1 ) { // 断点下载，继续进行下载
                    $data['data'] = array(
                        'IsSuccess' => true,
                        'msg' => IBOS::lang( 'Upgrade downloading file', '', array( '{file}' => $curFile, '{percent}' => $percent, '{percent2}' => $percent2 ) ),
                        'url' => $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 2, 'fileseq' => $fileSeq, 'position' => ($position + $offset) ), $urlParam ) )
                    );
                } elseif ( $downloadStatus == 2 ) { // 下载完成,继续下一个
                    $data['data'] = array(
                        'IsSuccess' => true,
                        'msg' => IBOS::lang( 'Upgrade downloading file', '', array( '{file}' => $curFile, '{percent}' => $percent, '{percent2}' => $percent2 ) ),
                        'url' => $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 2, 'fileseq' => ($fileSeq + 1) ), $urlParam ) )
                    );
                } else {
                    // 尝试重新下载
                    $data['data'] = array(
                        'IsSuccess' => false,
                        'msg' => IBOS::lang( 'Upgrade redownload', '', array( '{file}' => $curFile ) ),
                        'url' => $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 2, 'fileseq' => $fileSeq ), $urlParam ) )
                    );
                }
                return $this->ajaxReturn( $data, 'json' );
            }
        } else {
            // 更新步骤缓存
            Upgrade::recordStep( 2 );
            $downloadUrl = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 2 ), $urlParam ) );
            $this->render( 'upgradeDownload', array( 'downloadUrl' => $downloadUrl ) );
        }
    }

    /**
     * 更新第三步：对比及显示差异文件
     * @param array $updateFileList 更新列表文件
     * @param array $urlParam url参数数组，用于生成并返回下一步链接
     * @param string $savePath 更新文件保存路劲
     * @return JsonString
     */
    private function processingCompareFile( $updateFileList, $urlParam, $savePath = '' ) {
        //筛选更新文件
        list($modifyList, $showList) = Upgrade::compareBasefile( $updateFileList );
        $data['step'] = 3;
//		if ( empty( $modifyList ) && empty( $showList ) ) {
//			$msg = IBOS::lang( 'Filecheck nofound md5file' );
//			$this->render( 'upgradeError', array( 'msg' => $msg ) );
//			exit();
//		} else {
        $list = array();
        foreach ( $updateFileList as $file ) {
            if ( isset( $modifyList[$file] ) ) {
                // 差异文件
                $list['diff'][] = $file;
            } elseif ( isset( $showList[$file] ) ) {
                // 普通文件
                $list['normal'][] = $file;
            } else {
                // 新文件
                $list['newfile'][] = $file;
            }
        }
        $backPath = './data/back/IBOS' . VERSION . ' Release[' . VERSION_DATE . ']';
        $data['data']['param'] = $urlParam;
        $data['data']['list'] = $list;
        $data['data']['url'] = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 4 ), $urlParam ) );
        $data['data']['forceUpgrade'] = !empty( $modifyList );
        $data['data']['msg'] = IBOS::lang( 'Upgrade comepare', '', array(
                    '{savePath}' => $savePath,
                    '{backPath}' => $backPath )
        );
//		}
        // 更新步骤缓存
        Upgrade::recordStep( 3 );
        $this->render( 'upgradeCompare', $data );
    }

    /**
     * 更新第四步：更新覆盖文件
     * @param array $upgradeInfo
     * @param array $updateFileList
     * @param string $upgradeStep
     * @param array $urlParam
     */
    private function processingUpdateFile( $upgradeInfo, $updateFileList, $upgradeStep, $urlParam ) {
        if ( Env::getRequest( 'coverStart' ) ) {
            $data['step'] = 4;
            $confirm = Env::getRequest( 'confirm' );
            $startUpgrade = Env::getRequest( 'startupgrade' );
            if ( !$confirm ) {
                // 返回设置ftp界面
                if ( Env::getRequest( 'ftpsetting' ) ) {
                    $param = array( 'step' => 4, 'confirm' => 'ftp' );
                    if ( $startUpgrade ) {
                        $param['startupgrade'] = 1;
                    }
                    $data['data']['status'] = 'ftpsetup';
                    $data['data']['url'] = $this->createUrl( 'upgrade/index', array_merge( $param, $urlParam ) );
                    $this->ajaxReturn( $data, 'json' );
                }
                // 检查是否有更新数据库  DEBUG::
                if ( $upgradeInfo['isupdatedb'] ) {
//					$fileList = array( 'data/update.php', 'install/data/install.sql', 'install/data/installData.sql' );
                    $fileList = array( 'data/update.php' );
                    $checkUpdateFileList = array_merge( $fileList, $updateFileList );
                } else {
                    $checkUpdateFileList = $updateFileList;
                }
                // 检查目录权限
                if ( File::checkFolderPerm( $checkUpdateFileList ) ) {
                    $confirm = 'file';
                } else {
                    // 没有权限，要设置ftp或重试。
                    $data['data']['status'] = 'no_access';
                    $data['data']['msg'] = IBOS::lang( 'Upgrade cannot access file' );
                    $data['data']['retryUrl'] = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 4 ), $urlParam ) );
                    $data['data']['ftpUrl'] = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 4, 'ftpsetting' => 1 ), $urlParam ) );
                    $this->ajaxReturn( $data, 'json' );
                }
            }
            $ftpParam = array();
            $ftpSetup = Env::getRequest( 'ftpsetup' );
            if ( $ftpSetup ) {
                foreach ( $ftpSetup as $key => $value ) {
                    $ftpParam["ftp[{$key}]"] = $value;
                }
            }
            // 还没开始升级的话
            if ( !$startUpgrade ) {
                // 先开始备份
                if ( !Env::getRequest( 'backfile' ) ) {
                    $param = array(
                        'step' => 4,
                        'backfile' => 1,
                        'confirm' => $confirm
                    );
                    $data['data']['status'] = 'upgrade_backuping';
                    $data['data']['msg'] = IBOS::lang( 'Upgrade backuping' );
                    $data['data']['url'] = $this->createUrl( 'upgrade/index', array_merge( $ftpParam, $param, $urlParam ) );
                    $this->ajaxReturn( $data, 'json' );
                }
                foreach ( $updateFileList as $updateFile ) {
                    $destFile = PATH_ROOT . '/' . $updateFile;
                    $backFile = PATH_ROOT . '/data/back/IBOS' . VERSION . ' Release[' . VERSION_DATE . ']/' . $updateFile;
                    if ( is_file( $destFile ) ) {
                        if ( !Upgrade::copyFile( $destFile, $backFile, 'file' ) ) {
                            $data['data']['status'] = 'upgrade_backup_error';
                            $data['data']['msg'] = IBOS::lang( 'Upgrade backup error' );
                            $this->ajaxReturn( $data, 'json' );
                        }
                    }
                }
                $data['data']['status'] = 'upgrade_backup_complete';
                $data['data']['msg'] = IBOS::lang( 'Upgrade backup complete' );
                $data['data']['url'] = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 4, 'startupgrade' => 1, 'confirm' => $confirm ), $ftpParam, $urlParam ) );
                $this->ajaxReturn( $data, 'json' );
            }
            // 开始升级
            // --- 覆盖文件 ---
            $param = array( 'step' => 4, 'startupgrade' => 1 );
            $url = $this->createUrl( 'upgrade/index', array_merge( $param, $urlParam, $ftpParam, array( 'confirm' => $confirm ) ) );
            $ftpUrl = $this->createUrl( 'upgrade/index', array_merge( $param, $urlParam, array( 'ftpsetting' => 1 ) ) );
            foreach ( $updateFileList as $updateFile ) {
                $srcFile = PATH_ROOT . '/data/update/IBOS' . $urlParam['version'] . ' Release[' . $urlParam['release'] . ']/' . $updateFile;
                if ( $confirm == 'ftp' ) {
                    $destFile = $updateFile;
                } else {
                    $destFile = PATH_ROOT . '/' . $updateFile;
                }
                // 覆盖旧文件
                if ( !Upgrade::copyFile( $srcFile, $destFile, $confirm ) ) {
                    Cache::model()->deleteByPk( 'upgrade_step' );
                    Cache::model()->deleteByPk( 'upgrade_run' );
                    $data['data']['ftpUrl'] = $ftpUrl;
                    $data['data']['retryUrl'] = $url;
                    if ( $confirm == 'ftp' ) {
                        $data['data']['status'] = 'upgrade_ftp_upload_error';
                        $data['data']['msg'] = IBOS::lang( 'Upgrade ftp upload error', '', array( '{file}' => $updateFile ) );
                    } else {
                        $data['data']['status'] = 'upgrade_copy_error';
                        $data['data']['msg'] = IBOS::lang( 'Upgrade copy error', '', array( '{file}' => $updateFile ) );
                    }
                    $this->ajaxReturn( $data, 'json' );
                }
            }
            // --- 覆盖操作完成 ---
            // -- 是否有数据库升级 --
            if ( $upgradeInfo['isupdatedb'] ) {
//				$dbUpdateFileArr = array( 'update.php', 'install/data/install.sql', 'install/data/installData.sql' );
                $dbUpdateFileArr = array( 'update.php' );
                foreach ( $dbUpdateFileArr as $dbUpdateFile ) {
                    $srcFile = PATH_ROOT . '/data/update/IBOS' . $urlParam['version'] . ' Release[' . $urlParam['release'] . ']/' . $dbUpdateFile;
                    $dbUpdateFile = $dbUpdateFile == 'update.php' ? 'data/update.php' : $dbUpdateFile;
                    if ( $confirm == 'ftp' ) {
                        $destFile = $dbUpdateFile;
                    } else {
                        $destFile = PATH_ROOT . '/' . $dbUpdateFile;
                    }
                    if ( !Upgrade::copyFile( $srcFile, $destFile, $confirm ) ) {
                        $data['data']['ftpUrl'] = $ftpUrl;
                        $data['data']['retryUrl'] = $url;
                        if ( $confirm == 'ftp' ) {
                            $data['data']['status'] = 'upgrade_ftp_upload_error';
                            $data['data']['msg'] = IBOS::lang( 'Upgrade ftp upload error', '', array( '{file}' => $dbUpdateFile ) );
                        } else {
                            $data['data']['status'] = 'upgrade_copy_error';
                            $data['data']['msg'] = IBOS::lang( 'Upgrade copy error', '', array( '{file}' => $dbUpdateFile ) );
                        }
                        $this->ajaxReturn( $data, 'json' );
                    }
                }
                $upgradeStep['step'] = 4;
                Cache::model()->add( array(
                    'cachekey' => 'upgrade_step',
                    'cachevalue' => serialize( $upgradeStep ),
                    'dateline' => TIMESTAMP,
                        ), false, true );
                // 直接访问数据库升级文件（此文件是data目录下刚生成的upgrade.php文件）
                $dbReturnUrl = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 5 ), $urlParam ) );
                $param = array(
                    'step' => 'prepare',
                    'from' => rawurlencode( $dbReturnUrl ),
                    'frommd5' => md5( rawurlencode( $dbReturnUrl ) . IBOS::app()->setting->get( 'config/security/authkey' ) )
                );
                $data['data']['status'] = 'upgrade_database';
                $data['data']['url'] = 'data/update.php?' . http_build_query( $param );
                $data['data']['msg'] = IBOS::lang( 'Upgrade file successful' );
                $this->ajaxReturn( $data, 'json' );
            }
            $data['data']['status'] = 'upgrade_file_successful';
            $data['data']['url'] = $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 5 ), $urlParam ) );
            $data['step'] = 5;
            $this->ajaxReturn( $data, 'json' );
        } else {
            // 更新步骤缓存
            Upgrade::recordStep( 4 );
            $data = array(
                'coverUrl' => $this->createUrl( 'upgrade/index', array_merge( array( 'step' => 4 ), $urlParam ) ),
                'to' => $upgradeInfo['latestversion'] . ' ' . $upgradeInfo['latestrelease'],
                'from' => VERSION . ' ' . VERSION_DATE
            );
            $this->render( 'upgradeCover', $data );
        }
    }

    /**
     * 更新第五步：删除临时文件，返回成功信息
     * @param array $urlParam url参数数组
     * @return JsonString
     */
    private function processingTempFile( $urlParam ) {
        $file = PATH_ROOT . '/data/update/IBOS ' . $urlParam['version'] . ' Release[' . $urlParam['release'] . ']/updatelist.tmp';
        $authKey = IBOS::app()->setting->get( 'config/security/authkey' );
        @unlink( $file );
        @unlink( PATH_ROOT . '/data/update.php' );
        Cache::model()->deleteByPk( 'upgrade_step' );
        Cache::model()->deleteByPk( 'upgrade_run' );
        Setting::model()->updateSettingValueByKey( 'upgrade', '' );
        $randomStr = StringUtil::random( 6 );
        $oldUpdateDir = '/data/update/';
        $newUpdateDir = '/data/update-' . $randomStr . '/';
        $oldBackDir = '/data/back/';
        $newBackDir = '/data/back-' . $randomStr . '/';
        File::copyDir( PATH_ROOT . $oldUpdateDir, PATH_ROOT . $newUpdateDir );
        File::copyDir( PATH_ROOT . $oldBackDir, PATH_ROOT . $newBackDir );
        File::clearDirs( PATH_ROOT . $oldUpdateDir );
        File::clearDirs( PATH_ROOT . $oldBackDir );
        $data['step'] = 5;
        $data['data']['url'] = $this->createUrl( 'upgrade/updateCache', array_merge( array( 'op' => "cache" ) ) );
        $data['data']['msg'] = IBOS::lang( 'Upgrade successful', '', array(
                    '{version}' => 'IBOS' . VERSION . ' ' . VERSION_DATE,
                    '{saveUpdateDir}' => $newUpdateDir,
                    '{saveBackDir}' => $newBackDir )
        );
        $this->render( 'upgradeSuccess', $data );
    }

    /**
     * 输出在线更新中错误信息
     */
    public function actionShowUpgradeErrorMsg() {
        $msg = Env::getRequest( 'msg' );
        $this->render( 'upgradeError', array( 'msg' => $msg ) );
    }

    public function actionUpdateCache() {
        $op = Env::getRequest( 'op' ) ? Env::getRequest( 'op' ) : "cache";
        switch ( $op ) {
            case "cache":
                CacheUtil::update();
                $op = "org";
                $msg = "正在更新静态文件缓存";
                $isSuccess = true;
                $isContinue = true;
                break;
            case "org":
                Org::update();
                $op = "module";
                $msg = "正在更新模块配置缓存";
                $isSuccess = true;
                $isContinue = true;
                break;
            case "module":
                Module::updateConfig();
                $op = "end";
                $msg = "缓存更新完成,记得要定期检查更新哦~";
                $isSuccess = true;
                $isContinue = false;
                break;
        }
        $param = array(
            'op' => $op,
            'msg' => $msg,
            'isSuccess' => $isSuccess,
            'isContinue' => $isContinue,
        );
        $this->ajaxReturn( $param, "json" );
    }

}
